import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

//和zk交互jdbc配置信息
public class GetJdbcConfig {
    private String driver = "";
    private String urlFormat = "";
    private String database = "";
    private String user = "";
    private String pwd = "";
    private ZkClient zkClient = null;
    private String path = "";

    //静态代码块设置单例模式
    private static class GetJdbcConfigHoler {
        private static GetJdbcConfig instance = new GetJdbcConfig();
    }

    public static GetJdbcConfig getInstance() {
        return GetJdbcConfigHoler.instance;
    }

    private GetJdbcConfig() {
        zkClient = new ZkClient("linux122:2181,linux121:2181,linux123:2181");
        zkClient.setZkSerializer(new ZkStrSerializer());
    }

    //注册watcher监听节点
    public void subscribeDataChanges() {
        zkClient.subscribeDataChanges(path, new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
                System.out.println("'"+ s + "' data changed, new data:\n" + o);
                //关闭连接池中的连接，根据新配置内容，重新建立连接
                ConnectionPool.getInstance().close();
                //获取新信息
                getFromZk();
                ConnectionPool.getInstance().init();
            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                System.out.println("'"+ s + "' data delete");
                ConnectionPool.getInstance().close();
//                GetJdbcConfig.getInstance().setToZk();
//                ConnectionPool.getInstance().init();
            }
        });
        System.out.println("subscribeDataChanges on '" + path + "' !");
    }

    //将配置信息发送到监听节点上
    public void setToZk() {
        if (!zkClient.exists(path)) zkClient.createPersistent(path);
        String conf = String.format("driver=%s\n" +
                "urlFormat=%s\n" +
                "database=%s\n" +
                "user=%s\n" +
                "pwd=%s\n",driver, urlFormat, database, user, pwd);
        zkClient.writeData(path, conf);
        System.out.println("update '" + path + "' data !");
    }

    //从监听节点获取配置信息
    public void getFromZk() {
        final Object o = zkClient.readData(path);
        final Properties properties = new Properties();
        try {
            properties.load(new StringReader((String) o));
            driver = properties.getProperty("driver");
            urlFormat = properties.getProperty("urlFormat");
            database = properties.getProperty("database");
            user = properties.getProperty("user");
            pwd = properties.getProperty("pwd");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("get data from '"+ path +"' !");
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return String.format(urlFormat, database);
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getDatabase() {
        return database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

//序列化
class ZkStrSerializer implements ZkSerializer {
    @Override
    public byte[] serialize(Object o) throws ZkMarshallingError {
        return String.valueOf(o).getBytes();
    }

    @Override
    public Object deserialize(byte[] bytes) throws ZkMarshallingError {
        return new String(bytes);
    }
}